/*
 *  flexchain.cpp
 *  EPPI-0.0
 *
 *  Created by Juan Carlos Garcia Orden on 22/01/08.
 *
 */

#include "flexchain.h"

FlexChain::FlexChain(ifstream &in, string cname, MecSystem *pSys)
:	Body(in,cname,pSys),
	firstP(),
	secondP(),
	matName(""),
	area(1.0),
	connectSurface()
{	
	dim = parentSystem->dim;	/** Must be set always.  dim belongs to the mother class Body */
	type = "flexchain";
	
	char keyword[20];
	string auxs;				/** Aux string */
	string auxs1;				/** Aux string */
	double auxd;				/** Aux double */
	int nPieces;				/** Number of pieces of the chain */
	int beginNum;				/** First point number */
	vector<string> auxsv;		/** Aux string vector */
	string firstName = "";			/** Name of the point at the first end */
	string secondName = "";			/** Name of the point at the second end */
	string na = "";
	char contactFileName[30];
	int numContact;
	string line;
	vector<string> vPNames;
	int i;
	ifstream inContact;	

	while (in >> keyword && strcmp(keyword,"ENDBODY") )
	{
		/** First end */
		if (!strcmp(keyword,"P1C") || !strcmp(keyword,"P1"))
		{
			if(!strcmp(keyword,"P1C"))	/** Input are cartesian coordinates */
			{
			in >> auxd;
			firstP.push_back(auxd);
			if( dim >= 2)
			{
				in >> auxd;
				firstP.push_back(auxd);
			}
			if( dim == 3)
			{
				in >> auxd;
				firstP.push_back(auxd);
			}
		}
			else if(!strcmp(keyword,"P1"))	/** Input is point name.  Coordinates must be extracted */
			{
			in >> firstName;		/** Read point name */
			firstP.resize(dim);
			if(checkForSlash(firstName)==false && !(parentSystem->pointNames).count(firstName))	/** P1 belongs to this system because does not have slash and it is in the point list */
			{
				addSystemName(firstName,parentSystem->name);
			}
			// Check if the point is local to the system or not
			if( parentSystem->checkIfPointSystem(firstName)==1 )
			{
				firstP = parentSystem->pointNames[firstName];	// The point is local to the system
			}
			else												// The point is NOT local to the system
			{
				na = getStringHead(firstName);	
				MecSystem* pm = parentSystem->getPTSystem(na);
				firstP = pm->pointNames[firstName];
			}
		}
			//else if(parentSystem->getProcNum()==parentSystem->getRankNum() ) cout << "*ERROR: Bad specification of first end of body " << name  << "\end";
		
			in >> auxs;					/** Second end */
			if(!auxs.compare("P2C"))	/** Input are cartesian coordinates */
			{
			in >> auxd;
			secondP.push_back(auxd);
			if( dim >= 2)
			{
				in >> auxd;
				secondP.push_back(auxd);
			}
			if( dim == 3)
			{
				in >> auxd;
				secondP.push_back(auxd);
			}
		}
			else if(!auxs.compare("P2"))	/** Input is point name. Coordinates must be extracted */
			{
			in >> secondName;		/** Read point name */
			secondP.resize(dim);
			if(checkForSlash(secondName)==false && !(parentSystem->pointNames).count(secondName))	/** P2 belongs to this system because does not have slash and it is in the point list */
			{
				addSystemName(secondName,parentSystem->name);
			}
			// Check if the point is local to the system or not
			if( parentSystem->checkIfPointSystem(secondName)==1 )
			{
				secondP = parentSystem->pointNames[secondName];	// The point is local to the system
			}
			else											// The point is NOT local to the system
			{
				na = getStringHead(secondName);	
				MecSystem* pm = parentSystem->getPTSystem(na);
				secondP = pm->pointNames[secondName];
			}
		}
			//else if(parentSystem->getProcNum()==0) cout << "*ERROR: Bad specification of second end of body " << name  << "\end";
		
			in >> auxs1;				/** Reads the AREA label */
			in >> area;					/** Reads the area value */
			in >> auxs1;				/** Reads the MAT label */
			in >> matName;				/** Reads the material name */
			in >> auxs1;				/** Reads the NPIECES label */
			in >> nPieces;				/**	Reads the npieces value */
			in >> auxs1;				/** Reads the BEGINNUM label */
			in >> beginNum;				/** Reads the beginnum value */

			int i;
			int j;
			stringstream pointNum;
			string pointName;				/** Point name */
			string ppointName;				/** Previous point name */
			vector<double> coords(dim);		/** Coordinates */
			vector<double> pcoords(dim);	/** Previous coordinates */
		
			for(i=1; i<=nPieces; i++)		/** Loop on the links */
			{
			if(i==1)					/** Fist piece */
			{
				if (firstName.compare("")) /** If first point given by name, it already exists */
				{
					ppointName = firstName;
				}
				else						/** first name is beginNum */
				{
					pointNum << beginNum;
					pointNum >> ppointName;
					addSystemName(ppointName,parentSystem->name);
					parentSystem->addPointName(ppointName,firstP);
					pointNum.clear();
				}
			}
			if(i==nPieces)					/** Last piece */
			{
				if (secondName.compare("")) /** If last point given by name, it already exists */
				{
					pointName = secondName;
				}
				else					/** last name is beginNum + nPieces + 1 */
				{
					pointNum <<  beginNum+nPieces;
					pointNum >>  pointName;
					addSystemName(pointName,parentSystem->name);
					parentSystem->addPointName(pointName,secondP);
					pointNum.clear();
				}
			}

			if(nPieces!=1 && i!=nPieces)	/** More than one piece, for all pieces but the last */
			{		
				auxd = (double(i))/(double(nPieces));
				pointNum << beginNum+i-1;						/** Point number "int" is casted to "string" */
				pointNum >> pointName;
				addSystemName(pointName,parentSystem->name);	/** System name is added to the point name */
				for(j=0;j<dim;j++) coords[j] = (firstP[j]+auxd*(secondP[j]-firstP[j]));	/** Computes coordinates of point */
				parentSystem->addPointName(pointName,coords);							/** Adds point name and coordinates at parent System */
				pointNum.clear();
			}

			auxsv.push_back(ppointName);
			auxsv.push_back(pointName);
			vComponents.push_back(new Truss(auxsv,area,matName,dim));
			
			connectSurface.push_back(auxsv);
			
			vPointNamesSurface.push_back(ppointName);
			
			pcoords = coords;	/** Save the generated point, to use at the next pass of the loop */
			ppointName = pointName;
			auxsv.clear();
			pointName.clear();
		}
			vPointNamesSurface.push_back(ppointName);	// Last point
			if(parentSystem->getProcNum()==0) cout << "	Body " << name << " succesfully read \n";
		}
		if (!strcmp(keyword,"CONTACTPOINTS"))
		{
			in >> auxs;
			if (!auxs.compare("all"))	contactAllOption = true;
			if (!auxs.compare("file"))
			{
				in >> contactFileName;
				contactFileOption = true;
			}
			if (!auxs.compare("names"))
			{
				contactNamesOption = true;
				getline(in,line);
				istringstream iss(line);
				while (iss >> keyword )
				{
					auxs = keyword;
					vPNames.push_back(auxs);
					//cout << "keyword is " << keyword << endl;
				}				
			}			
		}
	}
	// If nothing is said about contact, take by default the "all" option
	if (contactAllOption==false && contactFileOption==false && contactNamesOption==false)	contactAllOption = true;
	
	if (contactAllOption==true)
	{
		vPointNamesContact = vPointNamesSurface;
	}
	if (contactFileOption==true)
	{
		inContact.open(contactFileName);
		inContact >> numContact;
		for (i=0; i<numContact; ++i)
		{
			inContact >> auxs;
			vPointNamesContact.push_back(auxs);
		}
		inContact.close();
	}
	if (contactNamesOption==true)
	{
		for (i=0; i<vPNames.size(); ++i)	vPointNamesContact.push_back(vPNames[i]);
	}	
}

// ***

void FlexChain::setPTPointsComp()
{
	int j, k;
	vector<string> auxs;
	map<string, Point*, less<string> > maux;
	pair<string,Point*> mauxEntry;
	pair<string,int> sharedEntry;
	
	for(j=0; j<vComponents.size(); j++)		
	//Loop on the components
	{
		auxs = (vComponents[j]->getPointNames());
		for(k=0; k<auxs.size(); k++)		
		// Loop on the names of the points within each component
		{
			/** If the point it is not at the local process ... */
			if( (parentSystem->checkIfPointProcess(auxs[k]))==false )
			{
				/** ...  create it at root system, copying the original point from the remote process */
				parentSystem->createPointAtRoot( parentSystem->getPTPoint(auxs[k]) );
				/** ...  and add the name of the shared point at the remote process */
				parentSystem->addRemoteSharedPoint(auxs[k],parentSystem->getProcNum());
			}
			mauxEntry.first = auxs[k];
			mauxEntry.second = (parentSystem->getPTPointLocal(auxs[k]));
			maux.insert(mauxEntry);
		}
		vComponents[j]->setMPoints(maux);
		maux.clear();
	}
}

// ***

void FlexChain::setPTPointsLoad()
{
	int j, k;
	vector<string> auxs;
	map<string, Point*, less<string> > maux;
	pair<string,Point*> mauxEntry;
	pair<string,int> sharedEntry;
	
	for(j=0; j<vLoads.size(); j++)		
	//Loop on the Loads
	{
		auxs = (vLoads[j]->getPointNames());
		for(k=0; k<auxs.size(); k++)		
		// Loop on the names of the points within each component
		{
			/** If the point it is not at the local process ... */
			if( (parentSystem->checkIfPointProcess(auxs[k]))==false )
			{
				/** ...  create it at root system, copying the original point from the remote process */
				parentSystem->createPointAtRoot( parentSystem->getPTPoint(auxs[k]) );
				/** ...  and add the name of the shared point at the remote process */
				parentSystem->addRemoteSharedPoint(auxs[k],parentSystem->getProcNum());
			}
			mauxEntry.first = auxs[k];
			mauxEntry.second = (parentSystem->getPTPointLocal(auxs[k]));
			maux.insert(mauxEntry);
		}
		vLoads[j]->setMPoints(maux);
		maux.clear();
	}

}

// ***

void FlexChain::setPPointSurface()
{
	// Build the vector of pointers to the surface points
	vPPointSurface.resize(vPointNamesSurface.size());
	
	int i;
	string auxs;
	//vector<Point*>	vPoints(nNodes);	
	for(i=0;i<vPointNamesSurface.size();i++)
	{
		auxs = vPointNamesSurface[i];
		if(checkForSlash(auxs)==false)	addSystemName(auxs,parentSystem->name);
		vPPointSurface[i] = parentSystem->getPTPointLocal( auxs ); 
	}			
}

// ***

void FlexChain::setMatAtComp()
{
	int i;
	string matName;
	Material* mat;
	for(i=0; i<vComponents.size(); i++)
	{
		matName = vComponents[i]->getMatName();
		mat = parentSystem->getPTMaterial(matName);		
		vComponents[i]->setMatAtComp(mat);
	}
}

// ***

void FlexChain::getBoundary(vector<vector<string> >& connect)
{
/*
	cout << "Estos son los puntos ordenados \n";
	 int i;
	 for(i=0; i<vPointNamesSurface.size(); ++i)	cout << vPointNamesSurface[i] << "\n";
	 
	cout << "Esta es la conectividad \n";
	for(i=0; i<connectSurface.size(); ++i)	cout << connectSurface[i][0] << "\t" << connectSurface[i][1] << "\n";
*/
}

// ***
/*
void FlexChain::writeFileGraph(ofstream &fGraph, string& gFormat)
{}	
*/
// ***

void FlexChain::writeMSH(ofstream &fGraph)
{}

// ***

void FlexChain::writeVTU(ofstream &fGraph, bool& plotDispFlag, bool& plotProcFlag, bool& plotStressFlag)
{
	int i;
	int j;
	int nt;
	
	localFGraph << "<?xml version=\"1.0\"?>\n";
	localFGraph << "<VTKFile type=\"UnstructuredGrid\" version=\"0.1\" byte_order=\"LittleEndian\">\n";
	localFGraph << "	<UnstructuredGrid>\n";
	localFGraph << "		<Piece NumberOfPoints=\"" << vPointNamesSurface.size() << "\" NumberOfCells=\"" << connectSurface.size() << "\">\n";
	localFGraph << "			<Points>\n";
	localFGraph << "				<DataArray type=\"Float64\" NumberOfComponents=\"3\" format=\"ascii\">";
	for(i=0; i<vPPointSurface.size(); ++i)
	{
		localFGraph << "\n";
		localFGraph << "				";
		nt = vPPointSurface[i]->globalTNum.size();	// Number of translational dofs
		for (j=0; j<nt; ++j)
		{
			localFGraph << parentSystem->getDof( vPPointSurface[i]->globalTNum[j] ) << "\t"; 
		}
		if (nt<2) localFGraph << 0.0;	// Second coordinate, just in case is 1D
		if (nt<3) localFGraph << "\t" << 0.0;	// Third coordinate, just in case is 2D
	}
	localFGraph << "\n";
	localFGraph << "				</DataArray>\n";
	localFGraph << "			</Points>\n";
	localFGraph<< "			<Cells>\n";
	localFGraph << "				<DataArray type=\"Int32\" Name=\"connectivity\" format=\"ascii\">";
	for (i=0; i<connectSurface.size(); ++i)
	{
		localFGraph << "\n";
		localFGraph << "					";
		for (j=0; j<connectSurface[0].size() ; ++j) // edit
		{
			localFGraph << pNamePNumber[ connectSurface[i][j] ] << "\t";
		}
	}
	localFGraph << "\n";
	localFGraph << "				</DataArray>\n";
	localFGraph << "				<DataArray type=\"Int32\" Name=\"offsets\" format=\"ascii\">";
	localFGraph << "\n";
	localFGraph << "					";
	for (i=0; i<connectSurface.size(); ++i)
	{
		localFGraph << connectSurface[0].size()*(1+i) << "\t";
	}
	localFGraph << "\n";
	localFGraph << "				</DataArray>\n";
	localFGraph << "				<DataArray type=\"UInt8\" Name=\"types\" format=\"ascii\">";
	localFGraph << "\n";
	localFGraph << "					";
	for (i=0; i<connectSurface.size(); ++i)
	{
		localFGraph << 3 << "\t";
	}
	localFGraph << "\n";
	localFGraph << "				</DataArray>\n";
	localFGraph<< "			</Cells>\n";
	// Example of pointData
	/*
	 localFGraph << "			<PointData Scalars=\"scalars\">\n";
	 localFGraph << "				<DataArray type=\"Float64\" Name=\"scalars\" format=\"ascii\">";
	 localFGraph << "\n";
	 for (i=0; i<vPPointSurface.size(); ++i)
	 {
	 localFGraph << 0.4 << "\n";
	 }
	 localFGraph << "				</DataArray>\n";
	 localFGraph << "			</PointData>\n";
	 */
	localFGraph << "		</Piece>\n";
	localFGraph << "	</UnstructuredGrid>\n";
	localFGraph << "</VTKFile>\n";		
}

// ***

void FlexChain::writeOOGL(ofstream &fGraph)
{}

// ***

void FlexChain::writeFileTemp(const double& time, ofstream & outF)
{}

// ***

void FlexChain::setIniPosBody(vector<double>& iniValues)
{}